package com.jeehentor.utils;


import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;


/**
 * Redis工具类:<br/>
 * 常用类型:Value,Hash,List,Set,ZSet. <br/>
 * 其他类型:Cluster,Geo,HyperLogLog.<br/>
 * StringRedisTemplate:可操作 Value,Hash.<br/>
 * RedisTemplate:可操作 Value,Hash,List,Set,ZSet.<br/>
 * 示例：<br/><code>@Autowired<br/>private RedisUtils redisUtils;<br/><br/>
 * public void setData(){<br/>
 * redisUtils.value.set(k, v);<br/>
 * }<br/>
 * <code/>
 *
 * @author wzd
 * @version 1.0
 */
@Component("redisUtils")
@SuppressWarnings({"unchecked", "all"})
public class RedisUtils {

    public final Common common = new Common();
    public final ValuePlus value = new ValuePlus();
    public final HashPlus hash = new HashPlus();
    public final ListPlus list = new ListPlus();
    public final SetPlus set = new SetPlus();
    public final ZSetPlus zSet = new ZSetPlus();
    protected final long NOT_EXPIRE = -1;

    @Resource
    @Qualifier("redisTemplate")
    protected RedisTemplate redisTemplate;

    public RedisUtils() {
    }

    public <T> ValueOperations<String, T> getValueOperations() {
        ValueOperations<String, T> valueOperations = redisTemplate.opsForValue();
        return valueOperations;
    }

    public <T> HashOperations<String, String, T> getHashOperations() {
        HashOperations<String, String, T> hashOperations = redisTemplate.opsForHash();
        return hashOperations;
    }

    public <T> ListOperations<String, T> getListOperations() {
        ListOperations<String, T> listOperations = redisTemplate.opsForList();
        return listOperations;
    }

    public <T> SetOperations<String, T> getSetOperations() {
        SetOperations<String, T> setOperations = redisTemplate.opsForSet();
        return setOperations;
    }

    public <T> ZSetOperations<String, T> getZSetOperations() {
        ZSetOperations<String, T> zSetOperations = redisTemplate.opsForZSet();
        return zSetOperations;
    }

    /**
     * 随机数 50-70 秒
     * <p>
     * autoSeconds()*50~=50分钟，*60~=1小时，*60*2~=2小时，*60*24~=1天，*60*24*5~=5天
     *
     * @return long
     */
    public long autoSeconds() {
        return ((int) (Math.random() * 20) + 50);
    }

    /**
     * key相关操作 检测、删除、更新
     * delete, dump, hasKey, expire, type, rename
     *
     * @author jf
     * @version 1.0
     */
    public class Common {

        /**
         * 删除
         *
         * @param key
         */
        public void delete(final String key) {
            redisTemplate.delete(key);
        }

        /**
         * 批量删除key
         *
         * @param keys
         */
        public void delete(final Collection<String> keys) {
            redisTemplate.delete(keys);
        }

        /**
         * 删除集合对象
         *
         * @param collection 多个对象
         * @return
         */
        public long deleteObject(final Collection collection) {
            return redisTemplate.delete(collection);
        }

        /**
         * 序列化key
         *
         * @param key
         * @return byte[]
         */
        public byte[] dump(final String key) {
            return redisTemplate.dump(key);
        }

        /**
         * 是否存在key
         *
         * @param key
         * @return
         */
        public Boolean hasKey(final String key) {
            return redisTemplate.hasKey(key);
        }

        /**
         * 设置给定key生存时间..
         *
         * @param key
         * @param seconds 过期时间
         * @return
         */
        public Boolean expire(final String key, final long seconds) {
            return redisTemplate.expire(key, seconds, TimeUnit.SECONDS);
        }

        /**
         * 设置给定key生存时间..
         *
         * @param key
         * @param timeout
         * @param timeUnit TimeUnit.type [SECONDS，MINUTES，HOURS，DAYS]
         * @return
         */
        public Boolean expire(final String key, final long timeout, TimeUnit timeUnit) {
            return redisTemplate.expire(key, timeout, timeUnit);
        }

        /**
         * 将给定key的到期时间设置为日期时间戳。
         *
         * @param key
         * @param date
         * @return
         */
        public Boolean expireAt(final String key, final Date date) {
            return redisTemplate.expireAt(key, date);
        }

        /**
         * 查找与给定pattern匹配的所有键。
         *
         * @param pattern 例如：sys_dict:*
         * @return
         */
        public Set<String> keys(final String pattern) {
            return (Set<String>) redisTemplate.keys(pattern);
        }

        /**
         * 将给定的key移动到带有index数据库。
         *
         * @param key
         * @param dbIndex
         * @return
         */
        public Boolean move(final String key, final int dbIndex) {
            return redisTemplate.move(key, dbIndex);
        }

        /**
         * 从给定的key删除过期时间，key 将持久保持
         *
         * @param key
         * @return
         */
        public Boolean persist(final String key) {
            return redisTemplate.persist(key);
        }

        /**
         * 获取输入key生存时间并将其转换为给定的TimeUnit
         *
         * @param key      指定返回key
         * @param timeUnit 时间返回类型
         * @return
         */
        public Long getExpire(final String key, TimeUnit timeUnit) {
            return redisTemplate.getExpire(key, timeUnit);
        }

        /**
         * 返回 key 的剩余的过期时间
         *
         * @param key
         * @return
         */
        public  Long getExpire(final String key) {
            return redisTemplate.getExpire(key);
        }

        /**
         * 从当前数据库中随机返回一个 key
         *
         * @return
         */
        public String randomKey() {
            return (String) redisTemplate.randomKey();
        }

        /**
         * 修改 key 的名称
         *
         * @param oldKey
         * @param newKey
         */
        public void rename(final String oldKey, final String newKey) {
            redisTemplate.rename(oldKey, newKey);
        }

        /**
         * 仅当 newkey 不存在时，将 oldKey 改名为 newkey
         *
         * @param oldKey
         * @param newKey
         * @return
         */
        public Boolean renameIfAbsent(final String oldKey, final String newKey) {
            return redisTemplate.renameIfAbsent(oldKey, newKey);
        }

        /**
         * 返回 key 所储存的值的类型
         *
         * @param key
         * @return
         */
        public DataType type(final String key) {
            return redisTemplate.type(key);
        }
    }

    /**
     * @author jf
     * @version 1.0
     */
    public class ValuePlus {

        /**
         * 设置数据, 默认过期时间2小时
         *
         * @param key   键
         * @param value 值
         */
        public <T> void set(final String key, final T value) {
            set(key, value, (autoSeconds() * 60 * 2));
        }

        /**
         * 设置数据 & 过期时间
         *
         * @param key     键
         * @param value   值，自动JSON.toJSONString(value)
         * @param timeout 过期时间:默认时间单位为秒
         */
        public <T> void set(final String key, T value, long timeout) {
            set(key, value, timeout, TimeUnit.SECONDS);
        }

        /**
         * 设置数据 & 过期时间 & 指定时间单位
         *
         * @param key      键
         * @param value    值，自动JSON.toJSONString(value)
         * @param timeout  过期时间
         * @param timeUnit 过期时间单位
         */
        public <T> void set(final String key, T value, long timeout, TimeUnit timeUnit) {
            getValueOperations().set(key, value);
            if (timeout != NOT_EXPIRE) {
                redisTemplate.expire(key, timeout, timeUnit);
            }
        }

        /**
         * 添加持久化数据
         *
         * @param key   键
         * @param value 设置指定 key 的值，无过期时间
         */
        public <T> void setNotExpire(final String key, final T value) {
            set(key, value, NOT_EXPIRE);
        }


        /**
         * 设置ASCII码, 字符串'a'的ASCII码是97, 转为二进制是'01100001', 此方法是将二进制第offset位值变为value
         * 设置存储在key中的 value 中offset处的位。
         *
         * @param key    键
         * @param offset 位置
         * @param value  值
         * @return
         */

        public Boolean setBit(final String key, final long offset, final boolean value) {
            return getValueOperations().setBit(key, offset, value);
        }

        /**
         * 如果key不存在，则设置key以保存字符串value 。
         *
         * @param key
         * @param value
         * @return
         */
        public <T> Boolean setIfAbsent(final String key, final T value) {
            return setIfAbsent(key, value, NOT_EXPIRE, null);
        }

        /**
         * 如果key不存在，则设置key以保存字符串value和过期timeout 。
         *
         * @param key
         * @param value
         * @param seconds 秒
         * @return
         */
        public <T> Boolean setIfAbsent(final String key, final T value, final long seconds) {
            return setIfAbsent(key, value, seconds, TimeUnit.SECONDS);
        }
        public <T> Boolean setIfAbsent(final String key, final T value, final long seconds, TimeUnit unit) {
            if (seconds != NOT_EXPIRE && seconds > 0) {
                return getValueOperations().setIfAbsent(key, value, seconds, unit);
            }
            return getValueOperations().setIfAbsent(key, value);
        }

        /**
         * 用 value 参数覆写给定 key 所储存的字符串值，从偏移量 offset 开始
         *
         * @param key
         * @param value
         * @param offset
         */
        public <T> void setRange(final String key, final T value, final long offset) {
            getValueOperations().set(key, value, offset);
        }

        /**
         * 批量添加
         *
         * @param maps
         */
        public void setMulti(final Map<String, String> maps) {
            getValueOperations().multiSet(maps);
        }

        /**
         * 仅当提供的key不存在时，才同时设置一个或多个 key-value
         *
         * @param maps
         * @return
         */
        public Boolean setMultiIfAbsent(final Map<String, String> maps) {
            return getValueOperations().multiSetIfAbsent(maps);
        }
        /**
         * 获取指定 key 的值
         *
         * @param key
         * @return
         */
        public <T> T get(final String key) {
            return get(key, NOT_EXPIRE);
        }

        /**
         * 获取数据 & 更新过期时间
         *
         * @param key
         * @param expire
         * @return
         */
        public <T> T get(final String key, final long expire) {
            if (expire != NOT_EXPIRE) {
                redisTemplate.expire(key, expire, TimeUnit.SECONDS);
            }
            return (T) getValueOperations().get(key);
        }


        /**
         * 获取对应class数据
         *
         * @param key
         * @param clazz
         * @param <T>
         * @return
         */
        public <T> T get(final String key, final Class<T> clazz) {
            return get(key, clazz, NOT_EXPIRE);
        }

        /**
         * 获取对应class数据 & 更新key的过期时间
         *
         * @param key
         * @param clazz
         * @param expire
         * @param <T>
         * @return
         */
        public <T> T get(final String key, final Class<T> clazz, final long expire) {
            String value = JSON.toJSONString(getValueOperations().get(key));
            if (expire != NOT_EXPIRE) {
                redisTemplate.expire(key, expire, TimeUnit.SECONDS);
            }
            return value == null ? null : JSON.parseObject(value, new TypeReference<T>() {
            });
        }

        /**
         * 返回 key 中字符串值的子字符
         *
         * @param key
         * @param start
         * @param end
         * @return
         */
        public String getRange(final String key, final long start, final long end) {
            return getValueOperations().get(key, start, end);
        }

        /**
         * 设置键的值并返回其旧值
         *
         * @param key
         * @param value
         * @return
         */

        public <T> T getAndSet(final String key, final T value) {
            return (T) getValueOperations().getAndSet(key, value);
        }

        /**
         * 对 key 所储存的字符串值，获取指定偏移量上的位(bit)
         *
         * @param key
         * @param offset
         * @return
         */

        public Boolean getBit(final String key, final long offset) {
            return getValueOperations().getBit(key, offset);
        }

        /**
         * 批量获取
         *
         * @param keys
         * @return
         */

        public List<String> multiGet(Collection<String> keys) {
            return JSON.parseObject(JSON.toJSONString(getValueOperations().multiGet(keys)),
                    new TypeReference<List<String>>() {
                    });
        }

        /**
         * 获取字符串的长度
         *
         * @param key
         * @return
         */

        public Long size(String key) {
            return getValueOperations().size(key);
        }

        /**
         * 增加(自增长), 负数则为自减
         * 将 key 下存储为字符串值的整数值增加 increment。
         *
         * @param key
         * @param increment
         * @return
         */
        public Long incrBy(String key, long increment) {
            return getValueOperations().increment(key, increment);
        }

        /**
         * 增加(自增长), 负数则为自减  浮点数
         * 通过 {@code increment} 将存储为 {@code key} 下的字符串值的浮点数值递增。
         *
         * @param key
         * @param increment
         * @return
         */
        public Double incrByFloat(String key, double increment) {
            return getValueOperations().increment(key, increment);
        }

        /**
         * 追加到末尾
         *
         * @param key
         * @param value
         * @return
         */

        public <T> Integer append(String key, T value) {
            return getValueOperations().append(key, JSON.toJSONString(value));
        }

    }
// *********************************************** hash相关操作

    /**
     * @author jf
     * @version 1.0
     */
    public class HashPlus {

        /**
         * 从 key 处的hash中获取给定 hashKey 的值。
         *
         * @param key
         * @param hashKey
         * @return
         */

        public <T> T get(String key, String hashKey) {
            return (T) getHashOperations().get(key, hashKey);
        }

        /**
         * 获取存储在 key 的整个hash。
         *
         * @param key
         * @return
         */

        public <T> Map<String, T> getHAll(String key) {
            return (Map<String, T>) getHashOperations().entries(key);
        }

        /**
         * 从 key 处的 hash 中获取给定 HK 的值。
         *
         * @param key
         * @param hashKeys
         * @return
         */

        public <T> List<T> getMulti(String key, Collection<String> hashKeys) {
            return (List<T>) getHashOperations().multiGet(key, hashKeys);
        }

        /**
         * 设置 hash 的 hashKey 的值<p>
         * H key, HK hashKey, HV value
         *
         * @param key
         * @param hashKey
         * @param value
         */

        public <T> void put(String key, String hashKey, T value) {
            getHashOperations().put(key, hashKey, value);
        }

        /**
         * 设置 hash 的一个或多个HK-HV值。
         *
         * @param key
         * @param maps
         */

        public <T> void putHAll(String key, Map<String, T> maps) {
            getHashOperations().putAll(key, maps);
        }

        /**
         * 仅当hashKey不存在时才设置
         *
         * @param key
         * @param hashKey
         * @param value
         * @return
         */

        public <T> Boolean putIfAbsent(String key, String hashKey, T value) {
            return getHashOperations().putIfAbsent(key, hashKey, value);
        }

        /**
         * 删除一个或多个哈希表字段
         *
         * @param key
         * @param hashKeys
         * @return
         */

        public Long delete(String key, Object... hashKeys) {
            return getHashOperations().delete(key, hashKeys);
        }

        /**
         * 确定给定的 hash hashKey 是否存在
         *
         * @param key
         * @param hashKey
         * @return
         */

        public Boolean exists(String key, Object hashKey) {
            return getHashOperations().hasKey(key, hashKey);
        }

        /**
         * 为哈希表 key 中的指定字段的整数值加上增量 increment<p>
         * 通过给定的增量增加 hash hashKey 的值。
         *
         * @param key
         * @param hashKey
         * @param increment
         * @return
         */

        public Long increment(String key, String hashKey, long increment) {
            return getHashOperations().increment(key, hashKey, increment);
        }

        /**
         * 为哈希表 key 中的指定字段的整数值加上增量 increment<p>
         * 通过给定的增量增加哈希 hashKey 的值。
         *
         * @param key
         * @param hashKey
         * @param delta
         * @return
         */

        public Double increment(String key, String hashKey, double delta) {
            return getHashOperations().increment(key, hashKey, delta);
        }

        /**
         * 在 key 处获取 hash 的键集（字段）。
         *
         * @param key
         * @return
         */

        public Set<String> keys(String key) {
            return getHashOperations().keys(key);
        }

        /**
         * 获取 key 的哈希大小。
         *
         * @param key
         * @return
         */

        public Long size(String key) {
            return getHashOperations().size(key);
        }

        /**
         * 获取哈希表中所有值<p>
         * 获取hash key条目集
         *
         * @param key
         * @return
         */

        public List<Object> values(String key) {
            return getHashOperations().values(key);
        }

        /**
         * 迭代哈希表中的键值对<p>
         * 使用 Cursor 迭代 key 处哈希中的条目。<p>
         * 重要提示：完成后调用 Cursor.close() 以避免资源泄漏。<p>
         *
         * @param key
         * @param options
         * @return
         * @throws IOException
         */

        public Cursor<Map.Entry<String, Object>> scan(String key, ScanOptions options) throws IOException {
            Cursor<Map.Entry<String, Object>> scan = getHashOperations().scan(key, options);
            scan.close();
            return scan;
        }
    }

    /**
     * @author jf
     * @version 1.0
     */
    public class ListPlus {


        /**
         * 通过索引获取列表中的元素
         *
         * @param key
         * @param index 正数： 从0|头部位置检索，负数：从尾部位置检索，-index值越小【-1 -2 -3】，检索位置越考前<p>
         *              【-index-size=index、【-3-4=1(index),-2-4=2(index)】<p>
         *              index     0        1        2       3<p>
         *              添加  【000Vlues 001Vlues 002Vlues 003Vlues】<p>
         *              检索+ 【000Vlues 001Vlues 002Vlues 003Vlues】<p>
         *              检索- 【-4：000Vlues -1：003Vlues -2：002Vlues -3：001Vlues】<p>
         * @return
         */

        public String index(String key, long index) {
            return JSON.toJSONString(getListOperations().index(key, index));
        }

        /**
         * 获取列表指定范围内的元素
         *
         * @param key
         * @param start 开始位置
         * @param end   结束位置
         * @return
         */

        public <T> List<T> range(String key, long start, long end) {
            return (List<T>) getListOperations().range(key, start, end);
        }

        /**
         * 存储在list头部
         *
         * @param key
         * @param value
         * @return
         */

        public <T> Long leftPush(String key, T value) {
            return getListOperations().leftPush(key, value);
        }

        /**
         * 存储在list头部
         *
         * @param key
         * @param value
         * @return
         */

        public <T> Long leftPushAll(String key, T... value) {
            return getListOperations().leftPushAll(key, value);
        }

        /**
         * 存储在list头部
         *
         * @param key
         * @param value
         * @return
         */

        public <T> Long leftPushAll(String key, Collection<T> value) {
            return getListOperations().leftPushAll(key, value);
        }

        /**
         * 当list存在的时候才加入
         *
         * @param key
         * @param value
         * @return
         */

        public <T> Long leftPushIfPresent(String key, T value) {
            return getListOperations().leftPushIfPresent(key, value);
        }

        /**
         * 如果pivot存在,再pivot前面添加
         *
         * @param key
         * @param pivot
         * @param value
         * @return
         */

        public <T> Long leftPush(String key, Object pivot, T value) {
            return getListOperations().leftPush(key, pivot, value);
        }

        /**
         * 存储在list尾部
         *
         * @param key
         * @param value
         * @return
         */
        public <T> Long rightPush(String key, T value) {
            return rightPush(key, value, NOT_EXPIRE, TimeUnit.SECONDS);
        }

        /**
         * 在pivot元素的右边添加值
         *
         * @param key
         * @param pivot
         * @param value
         * @return
         */
        public <T> Long rightPush(String key, Object pivot, T value) {
            return getListOperations().rightPush(key, pivot, value);
        }

        /**
         * 存储在list尾部+过期时间
         *
         * @param key
         * @param value
         * @param timeout 过期时间
         * @param unit    时间单位
         */
        public <T> Long rightPush(String key, T value, long timeout, TimeUnit unit) {
            Long r = getListOperations().rightPush(key, value);
            if (timeout > 0 && timeout != NOT_EXPIRE) {
                redisTemplate.expire(key, timeout, unit);
            }
            return r;
        }

        /**
         * 存储在list尾部
         *
         * @param key
         * @param value
         * @return
         */

        public <T> Long rightPushAll(String key, T... value) {
            return getListOperations().rightPushAll(key, value);
        }

        /**
         * 存储在list尾部
         *
         * @param key
         * @param value
         * @return
         */

        public <T> Long rightPushAll(String key, Collection<T> value) {
            return getListOperations().rightPushAll(key, value);
        }

        /**
         * 为已存在的列表添加值
         *
         * @param key
         * @param value
         * @return
         */

        public <T> Long rightPushIfPresent(String key, T value) {
            return getListOperations().rightPushIfPresent(key, value);
        }

        /**
         * 通过索引设置列表元素的值
         *
         * @param key
         * @param index
         * @param value
         */

        public <T> void set(String key, long index, T value) {
            getListOperations().set(key, index, value);
        }

        /**
         * 移出并获取列表的第一个元素
         *
         * @param key
         * @return
         */

        public String leftPop(String key) {
            return JSON.toJSONString(getListOperations().leftPop(key));
        }

        /**
         * 移出并获取列表的第一个元素， 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
         *
         * @param key
         * @param timeout
         * @param timeUnit
         * @return
         */

        public String leftPop(String key, long timeout, TimeUnit timeUnit) {
            return JSON.toJSONString(getListOperations().leftPop(key, timeout, timeUnit));
        }

        /**
         * 移除并获取列表最后一个元素
         *
         * @param key
         * @return
         */

        public String rightPop(String key) {
            return JSON.toJSONString(getListOperations().rightPop(key));
        }

        /**
         * 移出并获取列表的最后一个元素， 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
         *
         * @param key
         * @param timeout
         * @param timeUnit
         * @return
         */

        public String rightPop(String key, long timeout, TimeUnit timeUnit) {
            return JSON.toJSONString(getListOperations().rightPop(key, timeout, timeUnit));
        }

        /**
         * 移除列表的最后一个元素，并将该元素添加到另一个列表并返回
         *
         * @param sourceKey
         * @param destinationKey
         * @return
         */

        public String rightPopAndLeftPush(String sourceKey, String destinationKey) {
            return JSON.toJSONString(getListOperations().rightPopAndLeftPush(sourceKey, destinationKey));
        }

        /**
         * 从列表中弹出一个值，将弹出的元素插入到另外一个列表中并返回它； 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
         *
         * @param sourceKey
         * @param destinationKey
         * @param timeout
         * @param timeUnit
         * @return
         */

        public String rightPopAndLeftPush(String sourceKey, String destinationKey, long timeout, TimeUnit timeUnit) {
            return JSON.toJSONString(getListOperations().rightPopAndLeftPush(sourceKey, destinationKey, timeout, timeUnit));
        }

        /**
         * 删除集合中值等于value得元素
         *
         * @param key
         * @param index
         * @param value
         * @return
         */

        public <T> Long remove(String key, long index, T value) {
            return getListOperations().remove(key, index, value);
        }

        /**
         * 裁剪list
         *
         * @param key
         * @param start
         * @param end
         */

        public void trim(String key, long start, long end) {
            getListOperations().trim(key, start, end);
        }

        /**
         * 获取列表长度
         *
         * @param key
         * @return
         */

        public Long size(String key) {
            return getListOperations().size(key);
        }

    }

    /**
     * @author jf
     * @version 1.0
     */
    public class SetPlus {

        /**
         * set添加元素
         *
         * @param key
         * @param values
         * @return
         */

        public <T> Long add(String key, T... values) {
            return getSetOperations().add(key, values);
        }

        /**
         * set移除元素
         *
         * @param key
         * @param values
         * @return
         */

        public Long remove(String key, Object... values) {
            return getSetOperations().remove(key, values);
        }

        /**
         * 移除并返回集合的一个随机元素
         *
         * @param key
         * @return
         */

        public String pop(String key) {
            return JSON.toJSONString(getSetOperations().pop(key));
        }

        /**
         * 将元素value从一个集合移到另一个集合
         *
         * @param key
         * @param value
         * @param destKey
         * @return
         */

        public <T> Boolean move(String key, T value, String destKey) {
            return getSetOperations().move(key, value, destKey);
        }

        /**
         * 获取集合的大小
         *
         * @param key
         * @return
         */

        public Long size(String key) {
            return getSetOperations().size(key);
        }

        /**
         * 判断集合是否包含value
         *
         * @param key
         * @param value
         * @return
         */

        public <T> Boolean isMember(String key, T value) {
            return getSetOperations().isMember(key, value);
        }

        /**
         * 获取两个集合的交集
         *
         * @param key
         * @param otherKey
         * @return
         */

        public Set<String> intersect(String key, String otherKey) {
            return JSON.parseObject(JSON.toJSONString(getSetOperations().intersect(key, otherKey)), new TypeReference<Set<String>>() {
            });
        }

        /**
         * 获取key集合与多个集合的交集
         *
         * @param key
         * @param otherKeys
         * @return
         */

        public Set<String> intersect(String key, Collection<String> otherKeys) {
            return JSON.parseObject(JSON.toJSONString(getSetOperations().intersect(key, otherKeys)), new TypeReference<Set<String>>() {
            });
        }

        /**
         * key集合与otherKey集合的交集存储到destKey集合中
         *
         * @param key
         * @param otherKey
         * @param destKey
         * @return
         */

        public Long intersectAndStore(String key, String otherKey, String destKey) {
            return getSetOperations().intersectAndStore(key, otherKey, destKey);
        }

        /**
         * key集合与多个集合的交集存储到destKey集合中
         *
         * @param key
         * @param otherKeys
         * @param destKey
         * @return
         */

        public Long intersectAndStore(String key, Collection<String> otherKeys, String destKey) {
            return getSetOperations().intersectAndStore(key, otherKeys, destKey);
        }

        /**
         * 获取两个集合的并集
         *
         * @param key
         * @param otherKeys
         * @return
         */

        public Set<String> union(String key, String otherKeys) {
            return JSON.parseObject(JSON.toJSONString(getSetOperations().union(key, otherKeys)), new TypeReference<Set<String>>() {
            });
        }

        /**
         * 获取key集合与多个集合的并集
         *
         * @param key
         * @param otherKeys
         * @return
         */

        public Set<String> union(String key, Collection<String> otherKeys) {
            return JSON.parseObject(JSON.toJSONString(getSetOperations().union(key, otherKeys)), new TypeReference<Set<String>>() {
            });
        }

        /**
         * key集合与otherKey集合的并集存储到destKey中
         *
         * @param key
         * @param otherKey
         * @param destKey
         * @return
         */

        public Long unionAndStore(String key, String otherKey, String destKey) {
            return getSetOperations().unionAndStore(key, otherKey, destKey);
        }

        /**
         * key集合与多个集合的并集存储到destKey中
         *
         * @param key
         * @param otherKeys
         * @param destKey
         * @return
         */

        public Long unionAndStore(String key, Collection<String> otherKeys, String destKey) {
            return getSetOperations().unionAndStore(key, otherKeys, destKey);
        }

        /**
         * 获取两个集合的差集
         *
         * @param key
         * @param otherKey
         * @return
         */

        public Set<String> difference(String key, String otherKey) {
            return JSON.parseObject(JSON.toJSONString(getSetOperations().difference(key, otherKey)), new TypeReference<Set<String>>() {
            });
        }

        /**
         * 获取key集合与多个集合的差集
         *
         * @param key
         * @param otherKeys
         * @return
         */

        public Set<String> difference(String key, Collection<String> otherKeys) {
            return JSON.parseObject(JSON.toJSONString(getSetOperations().difference(key, otherKeys)), new TypeReference<Set<String>>() {
            });
        }

        /**
         * key集合与otherKey集合的差集存储到destKey中
         *
         * @param key
         * @param otherKey
         * @param destKey
         * @return
         */

        public Long differenceAndStore(String key, String otherKey, String destKey) {
            return getSetOperations().differenceAndStore(key, otherKey, destKey);
        }

        /**
         * key集合与多个集合的差集存储到destKey中
         *
         * @param key
         * @param otherKeys
         * @param destKey
         * @return
         */

        public Long differenceAndStore(String key, Collection<String> otherKeys, String destKey) {
            return getSetOperations().differenceAndStore(key, otherKeys, destKey);
        }

        /**
         * 获取集合所有元素
         *
         * @param key
         * @return
         */

        public Set<String> members(String key) {
            return JSON.parseObject(JSON.toJSONString(getSetOperations().members(key)), new TypeReference<Set<String>>() {
            });
        }

        /**
         * 随机获取集合中的一个元素
         *
         * @param key
         * @return
         */

        public String randomMember(String key) {
            return JSON.toJSONString(getSetOperations().randomMember(key));
        }

        /**
         * 随机获取集合中count个元素
         *
         * @param key
         * @param count
         * @return
         */

        public List<String> randomMembers(String key, long count) {
            return JSON.parseObject(JSON.toJSONString(getSetOperations().randomMembers(key, count)), new TypeReference<List<String>>() {
            });
        }

        /**
         * 随机获取集合中count个元素并且去除重复的
         *
         * @param key
         * @param count
         * @return
         */

        public Set<String> distinctRandomMembers(String key, long count) {
            return JSON.parseObject(JSON.toJSONString(getSetOperations().distinctRandomMembers(key, count)), new TypeReference<Set<String>>() {
            });
        }

        /**
         * 使用迭代器获取元素
         *
         * @param key
         * @param options
         * @return
         * @throws IOException
         */

        public Cursor<String> scan(String key, ScanOptions options) throws IOException {
            Cursor<Object> scan = getSetOperations().scan(key, options);
            scan.close();
            return JSON.parseObject(JSON.toJSONString(scan), new TypeReference<Cursor<String>>() {
            });
        }
    }

    /**
     * @author jf
     * @version 1.0
     */
    public class ZSetPlus {

        /**
         * 添加元素,有序集合是按照元素的score值由小到大排列
         *
         * @param key
         * @param value
         * @param score
         * @return
         */

        public <T> Boolean add(String key, T value, double score) {
            return getZSetOperations().add(key, value, score);
        }

        /**
         * 添加元素,zSet按score由小到大排列
         *
         * @param key
         * @param values
         * @return
         */
        public Long add(String key, Set<ZSetOperations.TypedTuple<Object>> values) {
            return getZSetOperations().add(key, values);
        }

        /**
         * 移除
         *
         * @param key
         * @param values
         * @return
         */
        public Long remove(String key, Object... values) {
            return getZSetOperations().remove(key, values);
        }

        /**
         * 增加元素的score值，并返回增加后的值
         *
         * @param key
         * @param value
         * @param delta
         * @return
         */
        public <T> Double incrementScore(String key, T value, double delta) {
            return getZSetOperations().incrementScore(key, value, delta);
        }

        /**
         * 返回元素在集合的排名,有序集合是按照元素的score值由小到大排列
         *
         * @param key
         * @param value
         * @return
         */
        public <T> Long rank(String key, T value) {
            return getZSetOperations().rank(key, value);
        }

        /**
         * 返回元素在集合的排名,按元素的score值由大到小排列
         *
         * @param key
         * @param value
         * @return
         */
        public <T> Long reverseRank(String key, T value) {
            return getZSetOperations().reverseRank(key, value);
        }

        /**
         * 获取集合的元素, 从小到大排序
         *
         * @param key
         * @param start
         * @param end
         * @return
         */
        public Set<Object> range(String key, long start, long end) {
            return JSON.parseObject(JSON.toJSONString(getZSetOperations().range(key, start, end)), new TypeReference<Set<String>>() {
            });
        }

        /**
         * 获取集合元素, 并且把score值也获取
         *
         * @param key
         * @param start
         * @param end
         * @return
         */
        public Set<ZSetOperations.TypedTuple<Object>> rangeWithScores(String key, long start, long end) {
            return JSON.parseObject(JSON.toJSONString(getZSetOperations().rangeWithScores(key, start, end)), new TypeReference<Set<ZSetOperations.TypedTuple<String>>>() {
            });
        }

        /**
         * 根据Score值查询集合元素
         *
         * @param key
         * @param min
         * @param max
         * @return
         */
        public Set<String> rangeByScore(String key, double min, double max) {
            return JSON.parseObject(JSON.toJSONString(getZSetOperations().rangeByScore(key, min, max)), new TypeReference<Set<String>>() {
            });
        }

        /**
         * 根据Score值查询集合元素, 从小到大排序
         *
         * @param key
         * @param min
         * @param max
         * @return
         */
        public Set<ZSetOperations.TypedTuple<String>> rangeByScoreWithScores(String key, double min, double max) {
            return JSON.parseObject(JSON.toJSONString(getZSetOperations().rangeByScoreWithScores(key, min, max)), new TypeReference<Set<ZSetOperations.TypedTuple<String>>>() {
            });
        }

        /**
         * 根据score查询元素,s开始e结束位置
         *
         * @param key
         * @param min
         * @param max
         * @param start
         * @param end
         * @return
         */
        public Set<ZSetOperations.TypedTuple<String>> rangeByScoreWithScores(String key, double min, double max, long start, long end) {
            return JSON.parseObject(JSON.toJSONString(getZSetOperations().rangeByScoreWithScores(key, min, max, start, end)), new TypeReference<Set<ZSetOperations.TypedTuple<String>>>() {
            });
        }

        /**
         * 获取集合的元素, 从大到小排序
         *
         * @param key
         * @param start
         * @param end
         * @return
         */
        public Set<String> reverseRange(String key, long start, long end) {
            return JSON.parseObject(JSON.toJSONString(getZSetOperations().reverseRange(key, start, end)), new TypeReference<Set<String>>() {
            });
        }

        /**
         * 获取集合的元素, 从大到小排序, 并返回score值
         *
         * @param key
         * @param start
         * @param end
         * @return
         */
        Set<ZSetOperations.TypedTuple<String>> reverseRangeWithScores(String key, long start, long end) {
            return JSON.parseObject(JSON.toJSONString(getZSetOperations().reverseRangeWithScores(key, start, end)), new TypeReference<Set<ZSetOperations.TypedTuple<String>>>() {
            });
        }

        /**
         * 根据Score值查询集合元素, 从大到小排序
         *
         * @param key
         * @param min
         * @param max
         * @return
         */
        public Set<String> reverseRangeByScore(String key, double min, double max) {
            return JSON.parseObject(JSON.toJSONString(getZSetOperations().reverseRangeByScore(key, min, max)), new TypeReference<Set<String>>() {
            });
        }

        /**
         * 根据Score值查询集合元素, 从大到小排序
         *
         * @param key
         * @param min
         * @param max
         * @return
         */
        public Set<ZSetOperations.TypedTuple<String>> reverseRangeByScoreWithScores(String key, double min, double max) {
            return JSON.parseObject(JSON.toJSONString(getZSetOperations().reverseRangeByScoreWithScores(key, min, max)), new TypeReference<Set<ZSetOperations.TypedTuple<String>>>() {
            });
        }

        /**
         * 根据score查询,大到小,s开始e结束
         *
         * @param key
         * @param min
         * @param max
         * @param start
         * @param end
         * @return
         */
        public Set<String> reverseRangeByScore(String key, double min, double max, long start, long end) {
            return JSON.parseObject(JSON.toJSONString(getZSetOperations().reverseRangeByScore(key, min, max, start, end)), new TypeReference<Set<String>>() {
            });
        }

        /**
         * 根据score值获取集合元素数量
         *
         * @param key
         * @param min
         * @param max
         * @return
         */
        public Long count(String key, double min, double max) {
            return getZSetOperations().count(key, min, max);
        }

        /**
         * 返回使用给定key存储的有序集合的元素数。
         *
         * @param key
         * @return
         */

        public Long size(String key) {
            return getZSetOperations().size(key);
        }

        /**
         * 使用key获取排序集的大小。
         *
         * @param key
         * @return
         */

        public Long zCard(String key) {
            return getZSetOperations().zCard(key);
        }

        /**
         * 获取集合中value元素的score值
         *
         * @param key
         * @param value
         * @return
         */

        public <T> Double score(String key, T value) {
            return getZSetOperations().score(key, value);
        }

        /**
         * 移除指定索引位置的成员
         *
         * @param key
         * @param start
         * @param end
         * @return
         */
        public Long removeRange(String key, long start, long end) {
            return getZSetOperations().removeRange(key, start, end);
        }

        /**
         * 根据指定的score值的范围来移除成员
         *
         * @param key
         * @param min
         * @param max
         * @return
         */

        public Long removeRangeByScore(String key, double min, double max) {
            return getZSetOperations().removeRangeByScore(key, min, max);
        }

        /**
         * 获取key和otherKey的并集并存储在destKey中
         *
         * @param key
         * @param otherKey
         * @param destKey
         * @return
         */

        public Long unionAndStore(String key, String otherKey, String destKey) {
            return getZSetOperations().unionAndStore(key, otherKey, destKey);
        }

        /**
         * 获取key和多个集合并集并存在dKey中
         *
         * @param key
         * @param otherKeys
         * @param destKey
         * @return
         */

        public Long unionAndStore(String key, Collection<String> otherKeys, String destKey) {
            return getZSetOperations().unionAndStore(key, otherKeys, destKey);
        }

        /**
         * 交集
         *
         * @param key
         * @param otherKey
         * @param destKey
         * @return
         */

        public Long intersectAndStore(String key, String otherKey, String destKey) {
            return getZSetOperations().intersectAndStore(key, otherKey, destKey);
        }

        /**
         * 交集
         *
         * @param key
         * @param otherKeys
         * @param destKey
         * @return
         */

        public Long intersectAndStore(String key, Collection<String> otherKeys, String destKey) {
            return getZSetOperations().intersectAndStore(key, otherKeys, destKey);
        }

        /**
         * 使用迭代器获取
         *
         * @param key
         * @param options
         * @return
         * @throws IOException
         */

        public Cursor<ZSetOperations.TypedTuple<String>> scan(String key, ScanOptions options) throws IOException {
            Cursor<ZSetOperations.TypedTuple<Object>> scan = getZSetOperations().scan(key, options);
            scan.close();
            return JSON.parseObject(JSON.toJSONString(scan), new TypeReference<Cursor<ZSetOperations.TypedTuple<String>>>() {
            });
        }
    }
}


